package com.yun.zf.search.service.impl;

import cn.hutool.core.date.DateUtil;
import com.yun.zf.common.admin.dto.community.CommunityStatisticalDto;
import com.yun.zf.common.admin.dto.house.AdminHousePicDto;
import com.yun.zf.common.admin.model.house.HouseListMo;
import com.yun.zf.common.admin.model.search.CommunityIndexKey;
import com.yun.zf.common.admin.model.search.CommunitySearchMo;
import com.yun.zf.common.admin.model.search.HouseIndexKey;
import com.yun.zf.common.admin.model.search.HouseSearchMo;
import com.yun.zf.common.app.dto.detail.CommunityNearByDto;
import com.yun.zf.common.constant.Constants;
import com.yun.zf.common.esRes.CommunityResMo;
import com.yun.zf.common.esRes.HouseIndexResMo;
import com.yun.zf.search.mapper.CommunityMapper;
import com.yun.zf.search.mapper.HouseMapper;
import com.yun.zf.search.mapper.PictureMapper;
import com.yun.zf.search.mapper.StatisticalMapper;
import com.yun.zf.search.service.ESRestService;
import com.yun.zf.system.service.ZfSubwayStationService;
import com.yun.zf.system.utils.EsRestUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ESRestServiceImpl implements ESRestService {
    @Autowired
    private HouseMapper houseMapper;
    @Autowired
    private ZfSubwayStationService stationService;
    @Autowired
    private EsRestUtil esRestUtil;
    @Autowired
    private CommunityMapper communityMapper;
    @Autowired
    private StatisticalMapper statisticalMapper;
    @Autowired
    private PictureMapper pictureMapper;

    /**
     * 小区名称自动补全, 选择所在的城市小区自动补全
     *
     * @param text 名称
     * @return 返回id 省市区划代码，小区名称
     */
    @Override
    public List<Map<String, String>> communitySuggest(String text, Long cityCode) {
        //词项建议
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("cityCode", cityCode));
        //  sourceBuilder.query(queryBuilder);
        // 创建CompletionSuggestionBuilder
        CompletionSuggestionBuilder suggestionBuilder = SuggestBuilders.completionSuggestion("communityNameSuggest") // 指定字段名
                .size(10) // 设定返回数量
                .skipDuplicates(true)
                .analyzer("ik_smart"); // 去重
        // 配置context，选择当前城市下的小区
        CategoryQueryContext categoryQueryContext = CategoryQueryContext.builder().setCategory(cityCode.toString()).build();

        Map<String, List<? extends ToXContent>> contexts = new HashMap<>();
        List<CategoryQueryContext> list = new ArrayList<>();
        list.add(categoryQueryContext);
        contexts.put("city", list);  // 分类字段
        suggestionBuilder.contexts(contexts); // 设置contexts
        // 创建suggestBuilder并将completionBuilder添加进去
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("community-suggest", suggestionBuilder).setGlobalText(text);
        // 执行请求
        CompletionSuggestion suggestion = esRestUtil.termSuggest(Constants.ES_COMMUNITY_INDEX, suggestBuilder);
        //搜索结果状态信息
        List<Map<String, String>> suggestList = new ArrayList<>();
        for (CompletionSuggestion.Entry entry : suggestion.getEntries()) {
            log.info("text: " + entry.getText().string());
            for (CompletionSuggestion.Entry.Option option : entry) {
                String suggestText = option.getText().string();
                String streetName = option.getHit().getSourceAsMap().get("streetName").toString();
                // 小区名称
                String communityName = option.getHit().getSourceAsMap().get("communityName").toString();
                // 商圈
                List<String> business = (ArrayList<String>) option.getHit().getSourceAsMap().get("business");
                if (StringUtils.isNotEmpty(suggestText)){
                    Map<String, String> map = new HashMap();
                    map.put("suggestText", suggestText);
                    if (suggestText.equals(communityName)){
                        map.put("type","小区");
                        map.put("streetName",streetName);
                    }else if (business.contains(suggestText)){
                        map.put("type","商圈");
                    }
                    // 如果学校也放进补全提示信息中后，就取出来与学校字段进行对比
                    suggestList.add(map);
                }

                log.info("   suggest option : " + suggestText);
            }
        }
        return suggestList;
    }


    @Override
    public Map<String, Object> searchCommunitys(CommunitySearchMo communitySearchMo) {
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        String[] fields = {CommunityIndexKey.CID};
        //1 、 构建搜索条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 城市代码必须
        queryBuilder.must(QueryBuilders.termQuery(CommunityIndexKey.CITYCODE, communitySearchMo.getCityCode()));
        // 区域街道代码搜索
        if (StringUtils.isNotEmpty(communitySearchMo.getRegionCode())&&!"BX".equals(communitySearchMo.getRegionCode())){
            queryBuilder.must(QueryBuilders.termQuery(CommunityIndexKey.REGIONCODE,communitySearchMo.getRegionCode()));
        }
        if (StringUtils.isNotEmpty(communitySearchMo.getStreetCode())&&!"BX".equals(communitySearchMo.getStreetCode())){
            queryBuilder.must(QueryBuilders.termQuery(CommunityIndexKey.STREETCODE,communitySearchMo.getStreetCode()));
        }

        // 如果搜索框内容不为空
        if (StringUtils.isNotBlank(communitySearchMo.getContext())) {
            if (StringUtils.isEmpty(communitySearchMo.getCommunityType())|| "C".equals(communitySearchMo.getCommunityType())){
                queryBuilder.must(QueryBuilders.matchQuery(CommunityIndexKey.COMMUNITYNAME, communitySearchMo.getContext()).boost(2.0f));
            }
            // 如果为商圈，搜索补全接口会返回是商圈或者小区
            else if ("B".equals(communitySearchMo.getCommunityType())){
                queryBuilder.must(QueryBuilders.matchQuery(CommunityIndexKey.BUSINESS, communitySearchMo.getContext()).boost(2.0f));
            }else if ("S".equals(communitySearchMo.getCommunityType())){
                queryBuilder.filter(QueryBuilders.termQuery(CommunityIndexKey.EDUSCHOOLS, communitySearchMo.getContext() ).boost(2.0f));
            }

        }

        // 如果均价区间不为空则加上均价搜索
        if (StringUtils.isNotBlank(communitySearchMo.getAveragePrice())&&!"BX".equals(communitySearchMo.getAveragePrice())) {
            String minPrice = communitySearchMo.getAveragePrice().split("-")[0];
            String maxPrice = communitySearchMo.getAveragePrice().split("-")[1];
            queryBuilder.filter(QueryBuilders.rangeQuery(CommunityIndexKey.AVERAGEPRICE).gte(minPrice).lte(maxPrice));
        }
        // 如果楼龄不为空，则获取符合条件的楼龄范围
        if (StringUtils.isNotBlank(communitySearchMo.getCtyBuildYear())&&!"BX".equals(communitySearchMo.getCtyBuildYear())) {
            int nowYear = DateUtil.thisYear();
            int minYear = nowYear - Integer.parseInt(communitySearchMo.getCtyBuildYear().split("-")[0]);
            int maxYear = nowYear - Integer.parseInt(communitySearchMo.getCtyBuildYear().split("-")[1]);
            queryBuilder.filter(QueryBuilders.rangeQuery(CommunityIndexKey.CTYBUILDYEAR).gte(maxYear).lte(minYear));
        }
        // 如果地铁线不为空
        if (StringUtils.isNotEmpty(communitySearchMo.getSubway())){
            if (communitySearchMo.getSubway().equals("BX")){
                queryBuilder.filter(QueryBuilders.existsQuery(CommunityIndexKey.COMMUNITYSTATIONS));
            }else {
                // 如果站点选择不限，则查出当前地铁线下的所有站点
                if (communitySearchMo.getStations().equals("BX")){
                    List<String> stations = stationService.getStationPois(Long.parseLong(communitySearchMo.getSubway()));
                    queryBuilder.filter(QueryBuilders.termsQuery(CommunityIndexKey.COMMUNITYSTATIONS, stations));

                }else {
                    String [] stations = communitySearchMo.getStations().split(",");
                    queryBuilder.filter(QueryBuilders.termsQuery(CommunityIndexKey.COMMUNITYSTATIONS, stations));
                }
            }
        }

        // 如果地铁站点不为空
      /*  if (StringUtils.isNotEmpty(communitySearchMo.getStations())){
            if (communitySearchMo.getStations().equals("BX")){
                queryBuilder.filter(QueryBuilders.existsQuery(CommunityIndexKey.COMMUNITYSTATIONS));
            }
            String [] stations = communitySearchMo.getStations().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(CommunityIndexKey.COMMUNITYSTATIONS, stations));
        }*/
        searchQueryBuilder.withQuery(queryBuilder).withFields(fields);
        try {
            Map<String, Object> communityData = esRestUtil.searchDataPage(Constants.ES_COMMUNITY_INDEX, communitySearchMo.getCurrent(), communitySearchMo.getPageSize(), CommunityResMo.class, searchQueryBuilder);

            return communityData;
        } catch (Exception e) {

        }

        return null;
    }


    @Override
    public Map<String, Object> searchHouseBasic(HouseSearchMo searchMo) {
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        // 查询只返回小区ID 字段
        String[] fields = new String[]{HouseIndexKey.HID, HouseIndexKey.PROVINCECODE, HouseIndexKey.CITYCODE};
        //1 、 构建搜索条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        // 2、城市代码必传-----
        queryBuilder.must(QueryBuilders.termQuery(HouseIndexKey.CITYCODE, searchMo.getCityCode()));
        // 3、类型type必传-----
        queryBuilder.must(QueryBuilders.termQuery(HouseIndexKey.TYPE, searchMo.getType()));
        // 4、 房源编号不为空直接匹配
        if (StringUtils.isNotBlank(searchMo.getHouseNumber())) {
            queryBuilder.filter(QueryBuilders.termQuery(HouseIndexKey.HOUSENUMBER, searchMo.getHouseNumber()));
        }
        // 5、 匹配区域代码
        if (StringUtils.isNotBlank(searchMo.getRegionCode()) && !"BX".equals(searchMo.getRegionCode())) {
            queryBuilder.filter(QueryBuilders.termQuery(HouseIndexKey.REGIONCODE, searchMo.getRegionCode()));
        }
        // 6、 匹配街道代码
        if (StringUtils.isNotBlank(searchMo.getStreetCode()) && !"BX".equals(searchMo.getStreetCode())) {
            queryBuilder.filter(QueryBuilders.termQuery(HouseIndexKey.STREETCODE, searchMo.getStreetCode()));
        }
        //7、小区ID 匹配
        if (StringUtils.isNotBlank(searchMo.getCommunityId())) {
            String[] communityids = searchMo.getCommunityId().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(HouseIndexKey.communityId, communityids));
        }

        // 8、如果价格区间不为空则加上价格搜索
        if (StringUtils.isNotBlank(searchMo.getHopedPrice()) && !"BX".equals(searchMo.getHopedPrice())) {
            String minPrice = searchMo.getHopedPrice().split("-")[0];
            String maxPrice = searchMo.getHopedPrice().split("-")[1];
            queryBuilder.filter(QueryBuilders.rangeQuery(HouseIndexKey.HOPEDPRICE).gte(minPrice).lte(maxPrice));
        }

        // 9、匹配面积区间
        if (StringUtils.isNotBlank(searchMo.getArea()) && !"BX".equals(searchMo.getArea())) {
            String minArea = searchMo.getArea().split("-")[0];
            String maxArea = searchMo.getArea().split("-")[1];
            queryBuilder.filter(QueryBuilders.rangeQuery(HouseIndexKey.AREA).gte(minArea).lte(maxArea));
        }
        // 10.匹配房型
        if (StringUtils.isNotBlank(searchMo.getBedrooms()) && !"BX".equals(searchMo.getBedrooms())) {
            queryBuilder.filter(QueryBuilders.termQuery(HouseIndexKey.BEDROOMS, searchMo.getBedrooms()));
        }
        // todo 待补充查询条件-----
        // 11、匹配标签
        String tags = searchMo.getTags();
        if (StringUtils.isNotBlank(tags) && !"BX".equals(tags)) {
            String[] tgs = tags.split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(HouseIndexKey.TAGS, tgs));
        }
        // 12 匹配朝向 ，注意，这里使用的text 放入ES 中的数据不要为中文，容易被分词导致搜索不到
        if (StringUtils.isNotBlank(searchMo.getDirection()) && !"BX".equals(searchMo.getDirection())) {
            String[] directions = searchMo.getDirection().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(HouseIndexKey.DIRECTION, directions));
        }
        //14 匹配楼层
        if (StringUtils.isNotBlank(searchMo.getFloorTag()) && !"BX".equals(searchMo.getFloorTag())) {
            String[] floors = searchMo.getFloorTag().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(HouseIndexKey.FLOORTAG, floors));
        }
        // 15.匹配电梯
        if (StringUtils.isNotBlank(searchMo.getIsElevator()) && !"BX".equals(searchMo.getIsElevator())) {
            queryBuilder.filter(QueryBuilders.termQuery(HouseIndexKey.ISELEVATOR, searchMo.getIsElevator()));
        }
        // 16、匹配装修
        if (StringUtils.isNotBlank(searchMo.getFixtures()) && !"BX".equals(searchMo.getFixtures())) {
            String[] fixtures = searchMo.getFixtures().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(HouseIndexKey.FIXTURES, fixtures));
        }
        // 17.匹配楼龄
        if (StringUtils.isNotBlank(searchMo.getBuildYear()) && !"BX".equals(searchMo.getBuildYear())) {
            int minYear = Integer.parseInt(searchMo.getBuildYear().split("-")[0]);
            int maxYear = Integer.parseInt(searchMo.getBuildYear().split("-")[1]);
            int startYear = DateUtil.thisYear() - minYear;
            int ednYear = DateUtil.thisYear() - maxYear;
            // todo
            queryBuilder.filter(QueryBuilders.rangeQuery(HouseIndexKey.BUILDYEAR).gte(startYear).lte(ednYear));
        }

        // 18.匹配用途
        if (StringUtils.isNotBlank(searchMo.getHouseUse()) && !"BX".equals(searchMo.getHouseUse())) {
            String[] houseUses = searchMo.getHouseUse().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(HouseIndexKey.HOUSEUSE, houseUses));
        }
        // 16.匹配权属- 商品房。公房等
        if (StringUtils.isNotBlank(searchMo.getOwnerShip()) && !"BX".equals(searchMo.getOwnerShip())) {
            String[] ships = searchMo.getOwnerShip().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(HouseIndexKey.OWNERSHIP, ships));
        }

        // 17.匹配类型
        if (StringUtils.isNotBlank(searchMo.getBuildingType()) && !"BX".equals(searchMo.getBuildingType())) {
            String[] buildTypes = searchMo.getBuildingType().split(",");
            queryBuilder.filter(QueryBuilders.termsQuery(HouseIndexKey.BUILDINGTYPE, buildTypes));
        }

        // 出租方式匹配
        if (StringUtils.isNotBlank(searchMo.getRentType()) && !"BX".equals(searchMo.getRentType())) {
            queryBuilder.filter(QueryBuilders.termQuery(HouseIndexKey.RENTTYPE, searchMo.getRentType()));
        }
        // 匹配租期分两部分，年租 匹配单位年， 短租匹配单位为月
        if (StringUtils.isNotBlank(searchMo.getUnit()) && !"BX".equals(searchMo.getUnit())) {
            queryBuilder.filter(QueryBuilders.termQuery(HouseIndexKey.UNIT, searchMo.getUnit()));
        }


        searchQueryBuilder.withQuery(queryBuilder).withFields(fields);
        try {
            String index = "";
            if (searchMo.getType() == 1) {
                index = Constants.ES_HOUSE_RENT_INDEX;
            } else if (searchMo.getType() == 2) {
                index = Constants.ES_HOUSE_INDEX;
            }

            Map<String, Object> communityData = esRestUtil.searchDataPage(index, searchMo.getCurrent(), searchMo.getPageSize(), HouseIndexResMo.class, searchQueryBuilder);
            return communityData;
        } catch (Exception e) {

        }
        return null;
    }

    /**
     * 小区名称自动补全, 选择所在的城市小区自动补全
     *
     * @param text 名称
     * @return 返回id 省市区划代码，小区名称
     */
    @Override
    public List<Map<String, String>> communitySuggestToHouse(String text, Long cityCode) {
        //词项建议
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("cityCode", cityCode));
        //  sourceBuilder.query(queryBuilder);
        // 创建CompletionSuggestionBuilder
        CompletionSuggestionBuilder suggestionBuilder = SuggestBuilders.completionSuggestion("communityNameSuggest") // 指定字段名
                .size(10) // 设定返回数量
                .skipDuplicates(true)
                .analyzer("ik_smart"); // 去重
        // 配置context，选择当前城市下的小区
        CategoryQueryContext categoryQueryContext = CategoryQueryContext.builder().setCategory(cityCode.toString()).build();

        Map<String, List<? extends ToXContent>> contexts = new HashMap<>();
        List<CategoryQueryContext> list = new ArrayList<>();
        list.add(categoryQueryContext);
        contexts.put("city", list);  // 分类字段
        suggestionBuilder.contexts(contexts); // 设置contexts
        // 创建suggestBuilder并将completionBuilder添加进去
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("community-suggest", suggestionBuilder).setGlobalText(text);
        // 执行请求
        CompletionSuggestion suggestion = esRestUtil.termSuggest(Constants.ES_COMMUNITY_INDEX, suggestBuilder);
        //搜索结果状态信息
        List<Map<String, String>> suggestList = new ArrayList<>();
        for (CompletionSuggestion.Entry entry : suggestion.getEntries()) {
            log.info("text: " + entry.getText().string());
            for (CompletionSuggestion.Entry.Option option : entry) {
                String suggestText = option.getText().string();
                String id = option.getHit().getId();
                String provinceCode = option.getHit().getSourceAsMap().get("provinceCode").toString();
                String regionCode = option.getHit().getSourceAsMap().get("regionCode").toString();
                String streetCode = option.getHit().getSourceAsMap().get("streetCode").toString();
                Map<String, String> map = new HashMap();
                map.put("id", id);
                map.put("cityCode", cityCode.toString());
                map.put("provinceCode", provinceCode);
                map.put("suggestText", suggestText);
                map.put("regionCode", regionCode);
                map.put("streetCode", streetCode);
                suggestList.add(map);
                log.info("   suggest option : " + suggestText);
            }
        }
        return suggestList;
    }

    @Override
    public List<HouseListMo> houseBasic(Long provCode, Long cityCode, List<Long> ids) {
        List<HouseListMo> list = houseMapper.getHouseList(provCode, cityCode, ids);
        if (list != null && list.size() > 0) {
            for (HouseListMo mo : list
            ) {
                List<AdminHousePicDto> pics = pictureMapper.getPics(Long.parseLong(mo.getId()), provCode, cityCode, 1);
                if (pics.size() > 0) {
                    mo.setUrl(pics.get(0).getUrl());
                }
            }
        }
        return list;
    }

    @Override
    public List<CommunityNearByDto> getBasicCommunity(List<Long> ids) {
        List<CommunityNearByDto> list =     communityMapper.getBasicCommunity(ids);
        for (CommunityNearByDto near: list
        ) {
            List<CommunityStatisticalDto> statisticalDtos =  statisticalMapper.getStical(Long.parseLong(near.getId()));
            for (CommunityStatisticalDto cs:statisticalDtos
            ) {
                if (cs.getType()==1){
                    near.setRentTotal(cs.getTotal());
                }else  if (cs.getType()==2){
                    near.setSoldTotal(cs.getTotal());
                    near.setAveragePrice(cs.getAveragePrice());
                }
            }

        }

        return  list;
    }
}
